/*     */ package com.zimbra.cs.index;
/*     */ 
/*     */ import com.google.common.collect.ImmutableSet;
/*     */ import com.google.common.collect.LinkedHashMultimap;
/*     */ import com.google.common.collect.Lists;
/*     */ import com.google.common.collect.Multimap;
/*     */ import com.google.common.collect.Sets;
/*     */ import com.google.common.io.Closeables;
/*     */ import com.zimbra.common.localconfig.KnownKey;
/*     */ import com.zimbra.common.localconfig.LC;
/*     */ import com.zimbra.common.service.ServiceException;
/*     */ import com.zimbra.common.util.Log;
/*     */ import com.zimbra.common.util.ZimbraLog;
/*     */ import com.zimbra.cs.mailbox.Folder;
/*     */ import com.zimbra.cs.mailbox.MailItem.Type;
/*     */ import com.zimbra.cs.mailbox.Mailbox;
/*     */ import com.zimbra.cs.mailbox.MailboxIndex;
/*     */ import java.io.IOException;
/*     */ import java.util.ArrayList;
/*     */ import java.util.Collection;
/*     */ import java.util.List;
/*     */ import java.util.ListIterator;
/*     */ import java.util.Set;
/*     */ import org.apache.lucene.document.Document;
/*     */ import org.apache.lucene.index.Term;
/*     */ import org.apache.lucene.search.BooleanClause;
/*     */ import org.apache.lucene.search.BooleanClause.Occur;
/*     */ import org.apache.lucene.search.BooleanQuery;
/*     */ import org.apache.lucene.search.MultiPhraseQuery;
/*     */ import org.apache.lucene.search.Query;
/*     */ import org.apache.lucene.search.Sort;
/*     */ import org.apache.lucene.search.SortField;
/*     */ import org.apache.lucene.search.TermQuery;
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ public final class LuceneQueryOperation
/*     */   extends QueryOperation
/*     */ {
/*     */   private static final float DB_FIRST_TERM_FREQ_PERC;
/*     */   private int curHitNo;
/*     */   private boolean haveRunSearch;
/*     */   private String queryString;
/*     */   private Query luceneQuery;
/*     */   private List<Term> filterTerms;
/*     */   private DBQueryOperation dbOp;
/*     */   private final List<QueryInfo> queryInfo;
/*     */   private boolean hasSpamTrashSetting;
/*     */   private ZimbraTopDocs hits;
/*     */   private int topDocsLen;
/*     */   private int topDocsChunkSize;
/*     */   private ZimbraIndexSearcher searcher;
/*     */   private Sort sort;
/*     */   
/*     */   static
/*     */   {
/*  58 */     float f = 0.8F;
/*     */     try {
/*  60 */       f = Float.parseFloat(LC.search_dbfirst_term_percentage_cutoff.value());
/*     */     }
/*     */     catch (Exception e) {}
/*  63 */     if ((f < 0.0D) || (f > 1.0D)) {
/*  64 */       f = 0.8F;
/*     */     }
/*  66 */     DB_FIRST_TERM_FREQ_PERC = f;
/*     */   }
/*     */   
/*  69 */   public LuceneQueryOperation() { this.curHitNo = 0;
/*  70 */     this.haveRunSearch = false;
/*  71 */     this.queryString = "";
/*     */     
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*  85 */     this.queryInfo = Lists.newArrayList();
/*  86 */     this.hasSpamTrashSetting = false;
/*     */     
/*     */ 
/*  89 */     this.topDocsLen = 0;
/*  90 */     this.topDocsChunkSize = 2000;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public void addClause(String queryStr, Query query, boolean bool)
/*     */   {
/* 104 */     assert (!this.haveRunSearch);
/*     */     
/*     */ 
/* 107 */     if (((query instanceof BooleanQuery)) && (((BooleanQuery)query).clauses().isEmpty())) {
/* 108 */       return;
/*     */     }
/*     */     
/* 111 */     if (this.queryString.isEmpty()) {
/* 112 */       this.queryString = ((bool ? "" : "-") + queryStr);
/*     */     } else {
/* 114 */       this.queryString = (this.queryString + " " + (bool ? "" : "-") + queryStr);
/*     */     }
/*     */     
/* 117 */     if (bool) {
/* 118 */       if (this.luceneQuery == null) {
/* 119 */         this.luceneQuery = query;
/* 120 */       } else if ((this.luceneQuery instanceof BooleanQuery)) {
/* 121 */         ((BooleanQuery)this.luceneQuery).add(query, BooleanClause.Occur.MUST);
/* 122 */       } else if ((query instanceof BooleanQuery)) {
/* 123 */         ((BooleanQuery)query).add(this.luceneQuery, BooleanClause.Occur.MUST);
/* 124 */         this.luceneQuery = query;
/*     */       } else {
/* 126 */         BooleanQuery combined = new BooleanQuery();
/* 127 */         combined.add(this.luceneQuery, BooleanClause.Occur.MUST);
/* 128 */         combined.add(query, BooleanClause.Occur.MUST);
/* 129 */         this.luceneQuery = combined;
/*     */       }
/*     */     }
/* 132 */     else if (this.luceneQuery == null) {
/* 133 */       BooleanQuery negate = new BooleanQuery();
/* 134 */       negate.add(query, BooleanClause.Occur.MUST_NOT);
/* 135 */       this.luceneQuery = negate;
/* 136 */     } else if ((this.luceneQuery instanceof BooleanQuery)) {
/* 137 */       ((BooleanQuery)this.luceneQuery).add(query, BooleanClause.Occur.MUST_NOT);
/*     */     } else {
/* 139 */       BooleanQuery combined = new BooleanQuery();
/* 140 */       combined.add(this.luceneQuery, BooleanClause.Occur.MUST);
/* 141 */       combined.add(query, BooleanClause.Occur.MUST_NOT);
/* 142 */       this.luceneQuery = combined;
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   void addAndedClause(Query query, boolean bool)
/*     */   {
/* 157 */     assert (this.luceneQuery != null);
/* 158 */     this.haveRunSearch = false;
/* 159 */     this.curHitNo = 0;
/*     */     
/* 161 */     if ((this.luceneQuery instanceof BooleanQuery)) {
/* 162 */       BooleanQuery bquery = (BooleanQuery)this.luceneQuery;
/* 163 */       boolean orOnly = true;
/* 164 */       for (BooleanClause clause : bquery) {
/* 165 */         if (clause.getOccur() != BooleanClause.Occur.SHOULD) {
/* 166 */           orOnly = false;
/* 167 */           break;
/*     */         }
/*     */       }
/* 170 */       if (!orOnly) {
/* 171 */         bquery.add(new BooleanClause(query, bool ? BooleanClause.Occur.MUST : BooleanClause.Occur.MUST_NOT));
/* 172 */         return;
/*     */       }
/*     */     }
/*     */     
/* 176 */     BooleanQuery bquery = new BooleanQuery();
/* 177 */     bquery.add(new BooleanClause(this.luceneQuery, BooleanClause.Occur.MUST));
/* 178 */     bquery.add(new BooleanClause(query, bool ? BooleanClause.Occur.MUST : BooleanClause.Occur.MUST_NOT));
/* 179 */     this.luceneQuery = bquery;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   void addFilterClause(Term t)
/*     */   {
/* 193 */     this.haveRunSearch = false;
/* 194 */     this.curHitNo = 0;
/*     */     
/* 196 */     if (this.filterTerms == null) {
/* 197 */       this.filterTerms = new ArrayList();
/*     */     }
/* 199 */     this.filterTerms.add(t);
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */   void clearFilterClause()
/*     */   {
/* 206 */     this.filterTerms = null;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */   public void setQueryString(String value)
/*     */   {
/* 214 */     assert (this.queryString.isEmpty());
/* 215 */     this.queryString = value;
/*     */   }
/*     */   
/*     */   public String toQueryString()
/*     */   {
/* 220 */     return '(' + this.queryString + ')';
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */   boolean shouldExecuteDbFirst()
/*     */   {
/* 227 */     if ((this.searcher == null) || (this.luceneQuery == null)) {
/* 228 */       return true;
/*     */     }
/*     */     
/* 231 */     if ((this.luceneQuery instanceof TermQuery)) {
/* 232 */       TermQuery query = (TermQuery)this.luceneQuery;
/* 233 */       Term term = query.getTerm();
/* 234 */       long start = System.currentTimeMillis();
/*     */       try {
/* 236 */         int freq = this.searcher.docFreq(term);
/* 237 */         int docsCutoff = (int)(this.searcher.getIndexReader().numDocs() * DB_FIRST_TERM_FREQ_PERC);
/* 238 */         ZimbraLog.search.debug("LuceneDocFreq freq=%d,cutoff=%d(%d%%),elapsed=%d", new Object[] { Integer.valueOf(freq), Integer.valueOf(docsCutoff), Integer.valueOf((int)(100.0F * DB_FIRST_TERM_FREQ_PERC)), Long.valueOf(System.currentTimeMillis() - start) });
/*     */         
/* 240 */         if (freq > docsCutoff) {
/* 241 */           return true;
/*     */         }
/*     */       } catch (IOException e) {
/* 244 */         return false;
/*     */       }
/*     */     }
/*     */     
/*     */     try
/*     */     {
/* 250 */       fetchFirstResults(1000);
/* 251 */       if (getTotalHitCount() > 1000L)
/*     */       {
/*     */ 
/*     */ 
/*     */ 
/* 256 */         Set<Folder> targetFolders = this.dbOp.getTargetFolders();
/* 257 */         if ((targetFolders != null) && (targetFolders.size() > 0)) {
/* 258 */           long itemCount = getTotalItemCount(targetFolders);
/* 259 */           ZimbraLog.search.debug("lucene hits=%d, folders item count=%d", new Object[] { Long.valueOf(getTotalHitCount()), Long.valueOf(itemCount) });
/* 260 */           if (itemCount < getTotalHitCount()) {
/* 261 */             return true;
/*     */           }
/*     */         }
/* 264 */         int dbHitCount = this.dbOp.getDbHitCount();
/* 265 */         ZimbraLog.search.debug("EstimatedHits lucene=%d,db=%d", new Object[] { Long.valueOf(getTotalHitCount()), Integer.valueOf(dbHitCount) });
/* 266 */         if (dbHitCount < getTotalHitCount()) {
/* 267 */           return true;
/*     */         }
/*     */       }
/* 270 */       return false;
/*     */     } catch (ServiceException e) {}
/* 272 */     return false;
/*     */   }
/*     */   
/*     */   private long getTotalItemCount(Set<Folder> folders)
/*     */   {
/* 277 */     long total = 0L;
/* 278 */     for (Folder f : folders) {
/* 279 */       total += f.getItemCount();
/*     */     }
/* 281 */     return total;
/*     */   }
/*     */   
/*     */   public void close()
/*     */   {
/* 286 */     Closeables.closeQuietly(this.searcher);
/* 287 */     this.searcher = null;
/*     */   }
/*     */   
/*     */   private void fetchFirstResults(int initialChunkSize) {
/* 291 */     if (!this.haveRunSearch) {
/* 292 */       assert (this.curHitNo == 0);
/* 293 */       this.topDocsLen = (3 * initialChunkSize);
/* 294 */       runSearch();
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   LuceneResultsChunk getNextResultsChunk(int max)
/*     */   {
/* 305 */     if (!this.haveRunSearch) {
/* 306 */       fetchFirstResults(max);
/*     */     }
/*     */     
/* 309 */     long start = System.currentTimeMillis();
/* 310 */     LuceneResultsChunk result = new LuceneResultsChunk();
/* 311 */     int luceneLen = this.hits != null ? this.hits.getTotalHits() : 0;
/* 312 */     while ((result.size() < max) && (this.curHitNo < luceneLen)) {
/* 313 */       if (this.topDocsLen <= this.curHitNo) {
/* 314 */         this.topDocsLen += this.topDocsChunkSize;
/* 315 */         this.topDocsChunkSize *= 4;
/* 316 */         if (this.topDocsChunkSize > 1000000) {
/* 317 */           this.topDocsChunkSize = 1000000;
/*     */         }
/* 319 */         if (this.topDocsLen > luceneLen) {
/* 320 */           this.topDocsLen = luceneLen;
/*     */         }
/* 322 */         runSearch();
/*     */       }
/*     */       Document doc;
/*     */       try
/*     */       {
/* 327 */         doc = this.searcher.doc(this.hits.getScoreDoc(this.curHitNo).getDocumentID());
/*     */       } catch (Exception e) {
/* 329 */         ZimbraLog.search.error("Failed to retrieve Lucene document: %s", this.hits.getScoreDoc(this.curHitNo).getDocumentID().toString(), e);
/*     */         
/* 331 */         return result;
/*     */       }
/* 333 */       this.curHitNo += 1;
/* 334 */       String mbid = doc.get("l.mbox_blob_id");
/* 335 */       if (mbid != null) {
/*     */         try {
/* 337 */           result.addHit(Integer.parseInt(mbid), doc);
/*     */         } catch (NumberFormatException e) {
/* 339 */           ZimbraLog.search.error("Invalid MAILBOX_BLOB_ID: " + mbid, e);
/*     */         }
/*     */       }
/*     */     }
/* 343 */     ZimbraLog.search.debug("LuceneFetchDocs n=%d,elapsed=%d", new Object[] { Integer.valueOf(luceneLen), Long.valueOf(System.currentTimeMillis() - start) });
/* 344 */     return result;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   private void fixMustNotOnly(BooleanQuery query)
/*     */   {
/* 354 */     for (BooleanClause clause : query.clauses()) {
/* 355 */       if ((clause.getQuery() instanceof BooleanQuery)) {
/* 356 */         fixMustNotOnly((BooleanQuery)clause.getQuery());
/*     */       }
/* 358 */       if (clause.getOccur() != BooleanClause.Occur.MUST_NOT) {
/* 359 */         return;
/*     */       }
/*     */     }
/*     */     
/* 363 */     query.add(new TermQuery(new Term("l.partname", "top")), BooleanClause.Occur.SHOULD);
/*     */     
/* 365 */     Set<MailItem.Type> types = this.context.getParams().getTypes();
/* 366 */     if (types.contains(MailItem.Type.CONTACT)) {
/* 367 */       query.add(new TermQuery(new Term("l.partname", "CONTACT")), BooleanClause.Occur.SHOULD);
/*     */     }
/*     */     
/* 370 */     if (types.contains(MailItem.Type.NOTE)) {
/* 371 */       query.add(new TermQuery(new Term("l.partname", "NOTE")), BooleanClause.Occur.SHOULD);
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */   private void runSearch()
/*     */   {
/* 380 */     this.haveRunSearch = true;
/*     */     
/* 382 */     if (this.searcher == null) {
/* 383 */       this.hits = null;
/* 384 */       return;
/*     */     }
/*     */     try
/*     */     {
/* 388 */       if ((this.luceneQuery instanceof BooleanQuery)) {
/* 389 */         fixMustNotOnly((BooleanQuery)this.luceneQuery);
/*     */       }
/* 391 */       this.luceneQuery = expandLazyMultiPhraseQuery(this.luceneQuery);
/* 392 */       if (this.luceneQuery == null) {
/* 393 */         this.hits = null;
/* 394 */         return;
/*     */       }
/* 396 */       ZimbraTermsFilter filter = this.filterTerms != null ? new ZimbraTermsFilter(this.filterTerms) : null;
/* 397 */       long start = System.currentTimeMillis();
/* 398 */       if (this.sort == null) {
/* 399 */         this.hits = this.searcher.search(this.luceneQuery, filter, this.topDocsLen);
/*     */       } else {
/* 401 */         this.hits = this.searcher.search(this.luceneQuery, filter, this.topDocsLen, this.sort);
/*     */       }
/* 403 */       ZimbraLog.search.debug("LuceneSearch query=%s,n=%d,total=%d,elapsed=%d", new Object[] { this.luceneQuery, Integer.valueOf(this.topDocsLen), Integer.valueOf(this.hits.getTotalHits()), Long.valueOf(System.currentTimeMillis() - start) });
/*     */     }
/*     */     catch (IOException e) {
/* 406 */       ZimbraLog.search.error("Failed to search query=%s", this.luceneQuery, e);
/* 407 */       Closeables.closeQuietly(this.searcher);
/* 408 */       this.searcher = null;
/* 409 */       this.hits = null;
/*     */     }
/*     */   }
/*     */   
/*     */   private Query expandLazyMultiPhraseQuery(Query query) throws IOException {
/* 414 */     if ((query instanceof LazyMultiPhraseQuery)) {
/* 415 */       LazyMultiPhraseQuery lazy = (LazyMultiPhraseQuery)query;
/* 416 */       int max = LC.zimbra_index_wildcard_max_terms_expanded.intValue();
/* 417 */       MultiPhraseQuery mquery = new MultiPhraseQuery();
/* 418 */       for (Term[] terms : lazy.getTermArrays())
/* 419 */         if (terms.length != 1) {
/* 420 */           mquery.add(terms);
/*     */         }
/*     */         else {
/* 423 */           Term base = terms[0];
/* 424 */           if (!lazy.expand.contains(base)) {
/* 425 */             mquery.add(terms);
/*     */           }
/*     */           else {
/* 428 */             List<Term> expanded = Lists.newArrayList();
/* 429 */             ZimbraIndexReader.TermFieldEnumeration itr = this.searcher.getIndexReader().getTermsForField(base.field(), base.text());
/*     */             try {
/* 431 */               while (itr.hasMoreElements()) {
/* 432 */                 BrowseTerm term = (BrowseTerm)itr.nextElement();
/* 433 */                 if ((term == null) || (!term.getText().startsWith(base.text())) || 
/* 434 */                   (expanded.size() >= max)) {
/*     */                   break;
/*     */                 }
/* 437 */                 expanded.add(new Term(base.field(), term.getText()));
/*     */               }
/*     */               
/*     */             }
/*     */             finally
/*     */             {
/* 443 */               Closeables.closeQuietly(itr);
/*     */             }
/* 445 */             if (expanded.isEmpty()) {
/* 446 */               return null;
/*     */             }
/* 448 */             mquery.add((Term[])expanded.toArray(new Term[expanded.size()]));
/*     */           }
/*     */         }
/* 451 */       return mquery; }
/* 452 */     if ((query instanceof BooleanQuery)) {
/* 453 */       ListIterator<BooleanClause> itr = ((BooleanQuery)query).clauses().listIterator();
/* 454 */       while (itr.hasNext()) {
/* 455 */         BooleanClause clause = (BooleanClause)itr.next();
/* 456 */         Query result = expandLazyMultiPhraseQuery(clause.getQuery());
/* 457 */         if (result == null) {
/* 458 */           if (clause.isRequired()) {
/* 459 */             return null;
/*     */           }
/* 461 */           itr.remove();
/*     */         }
/* 463 */         else if (result != clause.getQuery()) {
/* 464 */           clause.setQuery(result);
/*     */         }
/*     */       }
/* 467 */       return ((BooleanQuery)query).clauses().isEmpty() ? null : query;
/*     */     }
/* 469 */     return query;
/*     */   }
/*     */   
/*     */ 
/*     */   public String toString()
/*     */   {
/* 475 */     return "LUCENE(" + this.luceneQuery + (hasSpamTrashSetting() ? " <ANYWHERE>" : "") + ")";
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */   private LuceneQueryOperation cloneInternal()
/*     */   {
/* 482 */     assert (!this.haveRunSearch);
/* 483 */     LuceneQueryOperation clone = (LuceneQueryOperation)super.clone();
/* 484 */     clone.luceneQuery = ((Query)this.luceneQuery.clone());
/* 485 */     return clone;
/*     */   }
/*     */   
/*     */   public Object clone()
/*     */   {
/* 490 */     assert (this.searcher == null);
/* 491 */     LuceneQueryOperation toRet = cloneInternal();
/* 492 */     if (this.dbOp != null) {
/* 493 */       toRet.dbOp = ((DBQueryOperation)this.dbOp.clone(this));
/*     */     }
/* 495 */     return toRet;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   Object clone(DBQueryOperation caller)
/*     */   {
/* 504 */     assert (this.searcher == null);
/* 505 */     LuceneQueryOperation toRet = cloneInternal();
/* 506 */     toRet.setDBOperation(caller);
/* 507 */     return toRet;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   private long getTotalHitCount()
/*     */   {
/* 516 */     return this.hits != null ? this.hits.getTotalHits() : 0L;
/*     */   }
/*     */   
/*     */   public long getCursorOffset()
/*     */   {
/* 521 */     return -1L;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */   void resetDocNum()
/*     */   {
/* 528 */     this.curHitNo = 0;
/*     */   }
/*     */   
/*     */   protected QueryOperation combineOps(QueryOperation other, boolean union)
/*     */   {
/* 533 */     assert (!this.haveRunSearch);
/*     */     
/* 535 */     if (union) {
/* 536 */       if (other.hasNoResults()) {
/* 537 */         this.queryInfo.addAll(other.getResultInfo());
/*     */         
/* 539 */         return this;
/*     */       }
/*     */     }
/* 542 */     else if (other.hasAllResults()) {
/* 543 */       if (other.hasSpamTrashSetting()) {
/* 544 */         forceHasSpamTrashSetting();
/*     */       }
/* 546 */       this.queryInfo.addAll(other.getResultInfo());
/*     */       
/* 548 */       return this;
/*     */     }
/*     */     
/*     */ 
/* 552 */     if ((other instanceof LuceneQueryOperation)) {
/* 553 */       LuceneQueryOperation otherLucene = (LuceneQueryOperation)other;
/* 554 */       if (union) {
/* 555 */         this.queryString = ('(' + this.queryString + ") OR (" + otherLucene.queryString + ')');
/*     */       } else {
/* 557 */         this.queryString = ('(' + this.queryString + ") AND (" + otherLucene.queryString + ')');
/*     */       }
/*     */       
/* 560 */       BooleanQuery top = new BooleanQuery();
/* 561 */       if (union) {
/* 562 */         if ((this.luceneQuery instanceof BooleanQuery)) {
/* 563 */           orCopy((BooleanQuery)this.luceneQuery, top);
/*     */         } else {
/* 565 */           top.add(new BooleanClause(this.luceneQuery, BooleanClause.Occur.SHOULD));
/*     */         }
/* 567 */         if ((otherLucene.luceneQuery instanceof BooleanQuery)) {
/* 568 */           orCopy((BooleanQuery)otherLucene.luceneQuery, top);
/*     */         } else {
/* 570 */           top.add(new BooleanClause(otherLucene.luceneQuery, BooleanClause.Occur.SHOULD));
/*     */         }
/*     */       } else {
/* 573 */         if ((this.luceneQuery instanceof BooleanQuery)) {
/* 574 */           andCopy((BooleanQuery)this.luceneQuery, top);
/*     */         } else {
/* 576 */           top.add(new BooleanClause(this.luceneQuery, BooleanClause.Occur.MUST));
/*     */         }
/* 578 */         if ((otherLucene.luceneQuery instanceof BooleanQuery)) {
/* 579 */           andCopy((BooleanQuery)otherLucene.luceneQuery, top);
/*     */         } else {
/* 581 */           top.add(new BooleanClause(otherLucene.luceneQuery, BooleanClause.Occur.MUST));
/*     */         }
/*     */       }
/* 584 */       this.luceneQuery = top;
/* 585 */       this.queryInfo.addAll(other.getResultInfo());
/* 586 */       if (other.hasSpamTrashSetting()) {
/* 587 */         forceHasSpamTrashSetting();
/*     */       }
/* 589 */       return this;
/*     */     }
/* 591 */     return null;
/*     */   }
/*     */   
/*     */   private void andCopy(BooleanQuery from, BooleanQuery to) {
/* 595 */     boolean allAnd = true;
/* 596 */     for (BooleanClause clause : from) {
/* 597 */       if (clause.getOccur() == BooleanClause.Occur.SHOULD) {
/* 598 */         allAnd = false;
/* 599 */         break;
/*     */       }
/*     */     }
/* 602 */     if (allAnd) {
/* 603 */       for (BooleanClause clause : from) {
/* 604 */         to.add(clause);
/*     */       }
/*     */     } else {
/* 607 */       to.add(new BooleanClause(from, BooleanClause.Occur.MUST));
/*     */     }
/*     */   }
/*     */   
/*     */   private void orCopy(BooleanQuery from, BooleanQuery to) {
/* 612 */     boolean allOr = true;
/* 613 */     for (BooleanClause clause : from) {
/* 614 */       if (clause.getOccur() != BooleanClause.Occur.SHOULD) {
/* 615 */         allOr = false;
/* 616 */         break;
/*     */       }
/*     */     }
/* 619 */     if (allOr) {
/* 620 */       for (BooleanClause clause : from) {
/* 621 */         to.add(clause);
/*     */       }
/*     */     } else {
/* 624 */       to.add(new BooleanClause(from, BooleanClause.Occur.SHOULD));
/*     */     }
/*     */   }
/*     */   
/*     */   void forceHasSpamTrashSetting()
/*     */   {
/* 630 */     this.hasSpamTrashSetting = true;
/*     */   }
/*     */   
/*     */   List<QueryInfo> getQueryInfo() {
/* 634 */     return this.queryInfo;
/*     */   }
/*     */   
/*     */   public String getQueryString() {
/* 638 */     return this.queryString;
/*     */   }
/*     */   
/*     */   public Query getQuery() {
/* 642 */     return this.luceneQuery;
/*     */   }
/*     */   
/*     */   boolean hasSpamTrashSetting()
/*     */   {
/* 647 */     return this.hasSpamTrashSetting;
/*     */   }
/*     */   
/*     */   boolean hasNoResults()
/*     */   {
/* 652 */     return false;
/*     */   }
/*     */   
/*     */   boolean hasAllResults()
/*     */   {
/* 657 */     return false;
/*     */   }
/*     */   
/*     */   QueryOperation expandLocalRemotePart(Mailbox mbox) throws ServiceException
/*     */   {
/* 662 */     return this;
/*     */   }
/*     */   
/*     */   QueryOperation ensureSpamTrashSetting(Mailbox mbox, boolean includeTrash, boolean includeSpam)
/*     */     throws ServiceException
/*     */   {
/* 668 */     DBQueryOperation dbOp = new DBQueryOperation();
/* 669 */     dbOp.setLuceneQueryOperation(this);
/* 670 */     return dbOp.ensureSpamTrashSetting(mbox, includeTrash, includeSpam);
/*     */   }
/*     */   
/*     */   Set<QueryTarget> getQueryTargets()
/*     */   {
/* 675 */     return ImmutableSet.of(QueryTarget.UNSPECIFIED);
/*     */   }
/*     */   
/*     */   void setDBOperation(DBQueryOperation op) {
/* 679 */     this.dbOp = op;
/*     */   }
/*     */   
/*     */   public void resetIterator() throws ServiceException
/*     */   {
/* 684 */     if (this.dbOp != null) {
/* 685 */       this.dbOp.resetIterator();
/*     */     }
/*     */   }
/*     */   
/*     */   public ZimbraHit getNext() throws ServiceException
/*     */   {
/* 691 */     if (this.dbOp != null) {
/* 692 */       return this.dbOp.getNext();
/*     */     }
/* 694 */     return null;
/*     */   }
/*     */   
/*     */   public ZimbraHit peekNext() throws ServiceException
/*     */   {
/* 699 */     if (this.dbOp != null) {
/* 700 */       return this.dbOp.peekNext();
/*     */     }
/* 702 */     return null;
/*     */   }
/*     */   
/*     */   public List<QueryInfo> getResultInfo()
/*     */   {
/* 707 */     List<QueryInfo> toRet = new ArrayList();
/* 708 */     toRet.addAll(this.queryInfo);
/* 709 */     if (this.dbOp != null) {
/* 710 */       toRet.addAll(this.dbOp.getQueryInfo());
/*     */     }
/* 712 */     return toRet;
/*     */   }
/*     */   
/*     */   QueryOperation optimize(Mailbox mbox)
/*     */   {
/* 717 */     return this;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */   void depthFirstRecurseInternal(QueryOperation.RecurseCallback cb)
/*     */   {
/* 724 */     cb.recurseCallback(this);
/*     */   }
/*     */   
/*     */   protected void depthFirstRecurse(QueryOperation.RecurseCallback cb)
/*     */   {
/* 729 */     if (this.dbOp != null) {
/* 730 */       this.dbOp.depthFirstRecurse(cb);
/*     */     } else {
/* 732 */       depthFirstRecurseInternal(cb);
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public void addQueryInfo(QueryInfo inf)
/*     */   {
/* 745 */     this.queryInfo.add(inf);
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */   protected final void begin(QueryOperation.QueryContext ctx)
/*     */     throws ServiceException
/*     */   {
/* 753 */     assert (!this.haveRunSearch);
/* 754 */     this.context = ctx;
/* 755 */     if (this.dbOp == null)
/*     */     {
/*     */ 
/* 758 */       this.dbOp = new DBQueryOperation();
/* 759 */       this.dbOp.setLuceneQueryOperation(this);
/* 760 */       this.dbOp.begin(ctx);
/*     */     } else {
/*     */       try {
/* 763 */         this.searcher = ctx.getMailbox().index.getIndexStore().openSearcher();
/*     */       } catch (IOException e) {
/* 765 */         throw ServiceException.FAILURE("Failed to open searcher", e);
/*     */       }
/* 767 */       this.sort = toLuceneSort(ctx.getResults().getSortBy());
/*     */     }
/*     */   }
/*     */   
/*     */   private Sort toLuceneSort(SortBy sortBy) {
/* 772 */     if (sortBy == null) {
/* 773 */       return null;
/*     */     }
/*     */     
/* 776 */     switch (sortBy.getKey()) {
/*     */     case NONE: 
/* 778 */       return null;
/*     */     case NAME: 
/*     */     case NAME_NATURAL_ORDER: 
/*     */     case SENDER: 
/* 782 */       return new Sort(new SortField("nameSort", 3, sortBy.getDirection() == SortBy.Direction.DESC));
/*     */     
/*     */     case SUBJECT: 
/* 785 */       return new Sort(new SortField("subjSort", 3, sortBy.getDirection() == SortBy.Direction.DESC));
/*     */     
/*     */     case SIZE: 
/* 788 */       return new Sort(new SortField("l.size", 6, sortBy.getDirection() == SortBy.Direction.DESC));
/*     */     
/*     */     case ATTACHMENT: 
/* 791 */       return new Sort(new SortField("hasAttach", 3, sortBy.getDirection() == SortBy.Direction.DESC));
/*     */     
/*     */     case FLAG: 
/* 794 */       return new Sort(new SortField("hasFlag", 3, sortBy.getDirection() == SortBy.Direction.DESC));
/*     */     
/*     */     case PRIORITY: 
/* 797 */       return new Sort(new SortField("priority", 3, sortBy.getDirection() == SortBy.Direction.DESC));
/*     */     
/*     */     case RCPT: 
/* 800 */       if (!$assertionsDisabled) throw new AssertionError(sortBy);
/*     */       break;
/*     */     }
/* 803 */     return new Sort(new SortField("l.date", 3, sortBy.getDirection() == SortBy.Direction.DESC));
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   static final class LuceneResultsChunk
/*     */   {
/* 813 */     private final Multimap<Integer, Document> hits = LinkedHashMultimap.create();
/*     */     
/*     */     Set<Integer> getIndexIds() {
/* 816 */       return this.hits.keySet();
/*     */     }
/*     */     
/*     */     int size() {
/* 820 */       return this.hits.size();
/*     */     }
/*     */     
/*     */     void addHit(int indexId, Document doc) {
/* 824 */       this.hits.put(Integer.valueOf(indexId), doc);
/*     */     }
/*     */     
/*     */     Collection<Document> getHit(int indexId) {
/* 828 */       return this.hits.get(Integer.valueOf(indexId));
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */   public static final class LazyMultiPhraseQuery
/*     */     extends MultiPhraseQuery
/*     */   {
/*     */     private static final long serialVersionUID = -6754267749628771968L;
/*     */     
/*     */ 
/* 841 */     private final Set<Term> expand = Sets.newIdentityHashSet();
/*     */     
/*     */     public void expand(Term term) {
/* 844 */       add(term);
/* 845 */       this.expand.add(term);
/*     */     }
/*     */   }
/*     */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/cs/index/LuceneQueryOperation.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */